package com.dhq.myapp.util.http

import okhttp3.Call
import okhttp3.Callback
import okhttp3.FormBody
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.Response
import okio.IOException
import java.io.File
import java.util.concurrent.TimeUnit

/**
 * DESC
 * Created by douhaoqiang on 2025/11/7.
 */
class OkHttpUtils private constructor() {
    private var okHttpClient: OkHttpClient

    companion object {
        @Volatile
        private var instance: OkHttpUtils? = null

        fun getInstance(): OkHttpUtils {
            return instance ?: synchronized(this) {
                instance ?: OkHttpUtils().also { instance = it }
            }
        }
    }

    init {
        okHttpClient = OkHttpClient.Builder()
            .connectTimeout(15, TimeUnit.SECONDS)
            .readTimeout(15, TimeUnit.SECONDS)
            .writeTimeout(15, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .build()
    }

    fun get(url: String,params: Map<String, String> = emptyMap(),callback: HttpCallback){
        get(url,params,emptyMap(),callback)
    }

    // 带参数和请求头的GET请求[2](@ref)[8](@ref)
    fun get(
        url: String,
        params: Map<String, String> = emptyMap(),
        headers: Map<String, String> = emptyMap(),
        callback: HttpCallback
    ) {
        val urlBuilder = url.toHttpUrlOrNull()?.newBuilder() ?: run {
            callback.onFailure("Invalid URL")
            return
        }

        // 添加查询参数
        params.forEach { (key, value) ->
            urlBuilder.addQueryParameter(key, value)
        }

        val requestBuilder = Request.Builder()
            .url(urlBuilder.build())

        // 添加请求头
        headers.forEach { (key, value) ->
            requestBuilder.addHeader(key, value)
        }

        val request = requestBuilder.build()

        okHttpClient.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                callback.onFailure(e.message ?: "Unknown error")
            }

            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    val responseBody = response.body?.string() ?: ""
                    callback.onSuccess(responseBody)
                } else {
                    callback.onFailure("HTTP error: ${response.code}")
                }
            }
        })
    }

    // POST表单提交[2](@ref)[8](@ref)
    fun postForm(
        url: String,
        formData: Map<String, String>,
        headers: Map<String, String> = emptyMap(),
        callback: HttpCallback
    ) {
        val formBodyBuilder = FormBody.Builder()
        formData.forEach { (key, value) ->
            formBodyBuilder.add(key, value)
        }

        post(url, formBodyBuilder.build(), headers, callback)
    }

    // POST JSON数据[4](@ref)
    fun postJson(
        url: String,
        jsonData: String,
        headers: Map<String, String> = emptyMap(),
        callback: HttpCallback
    ) {
        val mediaType = "application/json; charset=utf-8".toMediaTypeOrNull()
        val requestBody = RequestBody.create(mediaType, jsonData)

        val mutableHeaders = headers.toMutableMap()
        if (!mutableHeaders.containsKey("Content-Type")) {
            mutableHeaders["Content-Type"] = "application/json"
        }

        post(url, requestBody, mutableHeaders, callback)
    }

    // 通用POST方法[4](@ref)[8](@ref)
    private fun post(
        url: String,
        requestBody: RequestBody,
        headers: Map<String, String>,
        callback: HttpCallback
    ) {
        val requestBuilder = Request.Builder()
            .url(url)
            .post(requestBody)

        headers.forEach { (key, value) ->
            requestBuilder.addHeader(key, value)
        }

        val request = requestBuilder.build()

        okHttpClient.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                callback.onFailure(e.message ?: "Unknown error")
            }

            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    val responseBody = response.body?.string() ?: ""
                    callback.onSuccess(responseBody)
                } else {
                    callback.onFailure("HTTP error: ${response.code}")
                }
            }
        })
    }

    // 文件上传[3](@ref)[5](@ref)
    fun uploadFile(
        url: String,
        filePath: String,
        fileParamName: String = "file",
        additionalParams: Map<String, String> = emptyMap(),
        callback: HttpCallback
    ) {
        val file = File(filePath)
        if (!file.exists() || !file.isFile) {
            callback.onFailure("File does not exist")
            return
        }

        val requestBody = MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart(
                fileParamName,
                file.name,
                file.asRequestBody(getMediaType(filePath))
            )
            .apply {
                additionalParams.forEach { (key, value) ->
                    addFormDataPart(key, value)
                }
            }
            .build()

        post(url, requestBody, emptyMap(), callback)
    }

    private fun getMediaType(filePath: String): MediaType {
        return when {
            filePath.endsWith(".jpg") || filePath.endsWith(".jpeg") ->
                "image/jpeg".toMediaTypeOrNull()
            filePath.endsWith(".png") ->
                "image/png".toMediaTypeOrNull()
            filePath.endsWith(".mp4") ->
                "video/mp4".toMediaTypeOrNull()
            filePath.endsWith(".pdf") ->
                "application/pdf".toMediaTypeOrNull()
            else -> "application/octet-stream".toMediaTypeOrNull()
        } ?: "application/octet-stream".toMediaTypeOrNull()!!
    }

    // 取消所有请求
    fun cancelAllRequests() {
        okHttpClient.dispatcher.cancelAll()
    }
}

// 回调接口
interface HttpCallback {
    fun onSuccess(response: String)
    fun onFailure(errorMessage: String)
}